pub mod admin_auth;
pub mod blog_open;
pub mod blog_setting;

use crate::config::CFG;
use crate::controller::AppState;
use crate::util::{embed, format_lensize};
use crate::APP_STATE;
use hypers::prelude::{hook,Next, Request, Responder};
use serde_json::{from_value, Value};
use std::collections::HashMap;
use tera::{Error, Result, Tera};

#[hook]
pub async fn global(mut req: Request, next: &mut Next<'_>) -> impl Responder {
    let ctx = tera::Context::new();
    let mut view: Tera;
    if CFG.server.is_embed {
        view = Tera::default();
        for file in embed::Template::iter() {
            let filename = file.as_ref();
            view.add_raw_template(filename, embed::get_tpl_data(filename).as_str())
                .unwrap_or_default();
        }
    } else {
        // view = Tera::new(concat!(
        //     env!("CARGO_MANIFEST_DIR"),
        //     "/assert/templates/**/*"
        // ))
        // .unwrap_or_default();
        view = Tera::new("assert/templates/**/*").unwrap();
    }
    // 设置模板函数
    set_fn(&mut view);
    req.insert(APP_STATE, AppState { view, ctx });
    next.next(req).await
}

// 设置模板方法
pub fn set_fn(view: &mut Tera) {
    view.register_function("assert", assert);
    view.register_function("upload_url", upload_url);
    view.register_function("avatar", avatar);
    view.register_function("url_for", url_for);
    view.register_function("format_size", format_size);
    // view.register_function("settings", settings);
}
// 引入资源
fn assert(args: &HashMap<String, Value>) -> Result<Value> {
    let none = String::from("/static/none");
    match args.get("path") {
        Some(val) => match from_value::<String>(val.clone()) {
            Ok(v) => Ok(Value::String(format!("/static/{}", v))),
            Err(_) => Ok(Value::String(none)),
        },
        None => Ok(Value::String(none)),
    }
}
// 图片预览
fn upload_url(args: &HashMap<String, Value>) -> Result<Value> {
    let none = String::from("/upload/none");
    match args.get("path") {
        Some(val) => match from_value::<String>(val.clone()) {
            Ok(v) => Ok(Value::String(format!("{}{}", CFG.attach.upload_url, v))),
            Err(_) => Ok(Value::String(none)),
        },
        None => Ok(Value::String(none)),
    }
}
// 头像
fn avatar(args: &HashMap<String, Value>) -> Result<Value> {
    let default_avatar = format!("/static/{}", CFG.server.default_avatar);
    match args.get("path") {
        Some(val) => match from_value::<String>(val.clone()) {
            Ok(v) => Ok(Value::String(v)),
            Err(_) => Ok(Value::String(default_avatar)),
        },
        None => Ok(Value::String(default_avatar)),
    }
}

// 链接
pub fn url_for(args: &HashMap<String, Value>) -> Result<Value> {
    let name = args["name"]
        .as_str()
        .ok_or(Error::msg("`name` should be a string"))?;
    let empty_elements = Value::Array(vec![]);
    let elements_iter = args
        .get("elements")
        .unwrap_or(&empty_elements)
        .as_array()
        .ok_or(Error::msg("`elements` should be an array"))?
        .iter();
    let mut elements = vec![];
    for elem in elements_iter {
        elements.push(elem.as_str().ok_or(Error::msg(
            "`elements` array should contain only strings",
        ))?);
    }
    Ok(Value::String(name.to_owned()))
}

// 格式化大小
fn format_size(args: &HashMap<String, Value>) -> Result<Value> {
    let zero = "0".to_owned();
    match args.get("size") {
        Some(val) => match from_value::<u64>(val.clone()) {
            Ok(v) => Ok(Value::String(format_lensize(v))),
            Err(_) => Ok(Value::String(zero)),
        },
        None => Ok(Value::String(zero)),
    }
}
// 设置
// pub fn settings(args: &HashMap<String, Value>) -> WebResult<Value, Error> {
//     let name = args["name"]
//         .as_str()
//         .ok_or(Error::Other("`name` should be a string".to_owned()))?;

//     SETTINGS.with(|data| {
//         let mut data_option = data.borrow_mut();
//         let datas = data_option.as_mut().ok_or(Error::Other(
//             "`settings` should only be called in request context".to_owned(),
//         ))?;

//         let mut res: String = "".to_string();
//         if let Some(k) = datas.get(name) {
//             res = k.parse::<String>().unwrap_or("".into());
//         }

//         Ok(Value::String(res))
//     })
// }
// https://github.com/deatil/nako-blog.git